Skip to content

Migrate OTel observer LLM span to typed event#142

Merged
chris-colinsky merged 2 commits into
mainfrom
feature/0049-pr3b-otel-typed-migration
Jun 8, 2026
Merged

Migrate OTel observer LLM span to typed event#142
chris-colinsky merged 2 commits into
mainfrom
feature/0049-pr3b-otel-typed-migration

Conversation

@chris-colinsky

Copy link
Copy Markdown
Member

Summary

  • Drive the openarmature.llm.complete span lifecycle from the typed LlmCompletionEvent on the success path. Span opens + closes in one shot at typed-event arrival, with start_time back-dated by latency_ms so the duration reflects the adapter-boundary measurement rather than dispatcher queue delay.
  • Failure-path spans continue to fire from the sentinel NodeEvent pair (the typed event is success-only per proposal 0049 alternative 3). The §5.5 attribute set is unchanged.
  • Flip OpenAIProvider.populate_caller_metadata default from False to True so the bundled OTel and Langfuse observers can emit the §5.6 openarmature.user.<key> span-attribute family without callers having to opt in. The spec-defined opt-in mechanism is preserved; only the python default flips.

Scope

PR 3b of the proposal 0049 + 0057 rollout (PR 3a landed in #141). Follow-up:

  • 3c: Langfuse observer migration to the typed event (same lifecycle shape).
  • 3d: Activate conformance fixtures 060-068 once 3c lands.

The provider still emits both the sentinel NodeEvent pair AND the typed LlmCompletionEvent during v0.13.0 per the dual-emit window. The sentinel pair drops in v0.15.0.

Behavior change worth calling out

OpenAIProvider(populate_caller_metadata=...) default flip is a public-API behavior change. Callers passing the kwarg explicitly are unaffected; callers relying on the default now get caller_invocation_metadata populated on every typed event, which surfaces as openarmature.user.* span attributes on the OTel LLM span. Pass populate_caller_metadata=False to suppress the snapshot if no downstream consumer needs it.

Test plan

  • uv run pytest tests/unit/test_observability_otel.py — 50 passed (added 3 new tests: span duration accuracy, latency_ms=None zero-duration fallback, disable_llm_spans on the typed path).
  • uv run pytest tests/ — 1203 passed across the full suite.
  • uv run pyright clean.
  • uv run ruff check + ruff format --check clean.
  • Conformance fixture 026-otel-caller-supplied-metadata passes (caller-metadata default flip restores the OTel span attribution that the migration would have otherwise lost).

Drive the openarmature.llm.complete span lifecycle from the typed
LlmCompletionEvent on the success path. The span opens and closes
in one shot at typed-event arrival, with start_time back-dated by
latency_ms so the duration reflects the adapter-boundary
measurement rather than dispatcher queue delay. Failure-path spans
continue to fire from the sentinel NodeEvent pair (the typed event
is success-only per proposal 0049 alternative 3). The §5.5
attribute set is unchanged.

Flip OpenAIProvider.populate_caller_metadata default from False to
True so the bundled OTel and Langfuse observers can emit the §5.6
openarmature.user.<key> span-attribute family without callers
having to opt in. The spec-defined opt-in mechanism is preserved;
only the python default flips.
Copilot AI review requested due to automatic review settings June 8, 2026 22:45

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Migrates the OpenTelemetry observer’s successful LLM span lifecycle (openarmature.llm.complete) from the legacy sentinel NodeEvent pair to the typed LlmCompletionEvent, including back-dating the span start time from latency_ms to reflect adapter-boundary latency. Also flips OpenAIProvider.populate_caller_metadata default to True so caller invocation metadata flows into observers by default.

Changes:

  • OTel observer now opens+closes the success-path LLM span on typed LlmCompletionEvent arrival and back-dates start_time using latency_ms; sentinel events remain for the error path during the dual-emit window.
  • OpenAI provider default now populates caller_invocation_metadata (opt-out remains available).
  • Updates/adds unit tests and introduces a shared typed-event test helper.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/openarmature/observability/otel/observer.py Drive success-path LLM spans from LlmCompletionEvent (with latency back-dating) and keep sentinel-based error spans.
src/openarmature/llm/providers/openai.py Flip populate_caller_metadata default to True and update rationale comments.
src/openarmature/graph/events.py Update LlmCompletionEvent documentation to reflect Python default caller-metadata behavior.
tests/unit/test_observability_otel.py Update observer tests to use typed events; add duration/latency and gating tests.
tests/unit/test_llm_provider.py Update tests for the new default caller-invocation-metadata behavior and opt-out.
tests/_helpers/typed_event.py Add helper to construct LlmCompletionEvent instances for tests.
CHANGELOG.md Document typed-event OTel span lifecycle change and OpenAI default flip.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/_helpers/typed_event.py Outdated
Comment thread src/openarmature/observability/otel/observer.py Outdated
Pass the typed LlmCompletionEvent to attribute_enrichers on the
success path instead of None; widens the enricher signature to
accept LlmCompletionEvent so enrichers can read LLM-call context
that the sentinel-pair path used to expose via the closing
NodeEvent.

Switch the shared typed-event test helper's default node_name and
namespace to "ask" so they reflect the calling-node semantics the
typed event documents, not the legacy sentinel value.
@chris-colinsky chris-colinsky merged commit 371545a into main Jun 8, 2026
6 checks passed
@chris-colinsky chris-colinsky deleted the feature/0049-pr3b-otel-typed-migration branch June 8, 2026 23:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants